﻿using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace SmartLib.UiComponents.Converters
{
	/// <summary>
	/// Conditional Value Converter
	/// </summary>
	[Serializable]
	[MarkupExtensionReturnType(typeof (IValueConverter))]
	[ValueConversion(typeof (object), typeof (bool))]
	public class ConditionalConverter : MarkupExtension, IValueConverter
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="ConditionalConverter"/> class.
		/// </summary>
		public ConditionalConverter()
		{
			Condition = ConverterCondition.Equals;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ConditionalConverter"/> class.
		/// </summary>
		/// <param name="condition">The condition.</param>
		public ConditionalConverter(ConverterCondition condition)
		{
			Condition = condition;
		}

		/// <summary>
		/// Gets or sets the condition.
		/// </summary>
		/// <value>The condition.</value>
		[DefaultValue(ConverterCondition.Equals)]
		public ConverterCondition Condition { get; set; }

		#region IValueConverter Members

		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value produced by the binding source.</param>
		/// <param name="targetType">The type of the binding target property.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			switch (Condition)
			{
				case ConverterCondition.Equals:
					return Equals(value, parameter);

				case ConverterCondition.NotEquals:
					return !Equals(value, parameter);

				case ConverterCondition.LessThan:
					{
						double dblValue;
						double dblParam;
						Convert(value, out dblValue, parameter, out dblParam);
						return dblValue < dblParam;
					}

				case ConverterCondition.LessThanAndEquals:
					{
						double dblValue;
						double dblParam;
						Convert(value, out dblValue, parameter, out dblParam);
						return dblValue <= dblParam;
					}

				case ConverterCondition.MoreThan:
					{
						double dblValue;
						double dblParam;
						Convert(value, out dblValue, parameter, out dblParam);
						return dblValue > dblParam;
					}

				case ConverterCondition.MoreThanAndEquals:
					{
						double dblValue;
						double dblParam;
						Convert(value, out dblValue, parameter, out dblParam);
						return dblValue >= dblParam;
					}

				case ConverterCondition.Contains:
					{
						string strValue;
						string strParam;
						Convert(value, out strValue, parameter, out strParam);
						return strValue.Contains(strParam);
					}
			}
			return DependencyProperty.UnsetValue;
		}

		/// <summary>
		/// Converts a value.
		/// </summary>
		/// <param name="value">The value that is produced by the binding target.</param>
		/// <param name="targetType">The type to convert to.</param>
		/// <param name="parameter">The converter parameter to use.</param>
		/// <param name="culture">The culture to use in the converter.</param>
		/// <returns>
		/// A converted value. If the method returns null, the valid null value is used.
		/// </returns>
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			return value;
		}

		#endregion

		/// <summary>
		/// Converts the specified value.
		/// </summary>
		/// <param name="value">The value.</param>
		/// <param name="dblValue">The DBL value.</param>
		/// <param name="parameter">The parameter.</param>
		/// <param name="dblParam">The DBL param.</param>
		private static void Convert(object value, out double dblValue, object parameter, out double dblParam)
		{
			if (value == null)
				throw new ArgumentNullException("value");
			if (parameter == null)
				throw new ArgumentNullException("parameter");

			if (!double.TryParse(value.ToString(), out dblValue))
				throw new FormatException("value must be numeric");

			if (!double.TryParse(parameter.ToString(), out dblParam))
				throw new FormatException("parameter must be numeric");
		}

		/// <summary>
		/// Converts the specified value.
		/// </summary>
		/// <param name="value">The value.</param>
		/// <param name="strValue">The STR value.</param>
		/// <param name="parameter">The parameter.</param>
		/// <param name="strParam">The STR param.</param>
		private static void Convert(object value, out string strValue, object parameter, out string strParam)
		{
			if (value == null)
				throw new ArgumentNullException("value");
			if (parameter == null)
				throw new ArgumentNullException("parameter");

			strValue = value as string;
			strParam = parameter as string;
		}

		/// <summary>
		/// When implemented in a derived class, returns an object that is set as the value of the target property for this markup extension.
		/// </summary>
		/// <param name="serviceProvider">Object that can provide services for the markup extension.</param>
		/// <returns>
		/// The object value to set on the property where the extension is applied.
		/// </returns>
		public override object ProvideValue(IServiceProvider serviceProvider)
		{
			return this;
		}
	}

	/// <summary>
	/// Converter Condition
	/// </summary>
	public enum ConverterCondition
	{
		/// <summary>
		/// Equals To Value
		/// </summary>
		Equals = 0,

		/// <summary>
		/// Less Than Value
		/// </summary>
		LessThan,

		/// <summary>
		/// Less Than And Equals
		/// </summary>
		LessThanAndEquals,

		/// <summary>
		/// More Than Value
		/// </summary>
		MoreThan,

		/// <summary>
		/// More Than And Equals
		/// </summary>
		MoreThanAndEquals,

		/// <summary>
		/// Not Equals To Value
		/// </summary>
		NotEquals,

		/// <summary>
		/// String contains passed value
		/// </summary>
		Contains,
	}
}